package com.wheel.autoconfigure.shiro.realm;

import com.wheel.autoconfigure.shiro.authorizing.AuthorizingDao;
import com.wheel.autoconfigure.shiro.authorizing.UsernamePasswordAuthenticationInfo;
import com.wheel.core.utils.Log;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.ArrayList;
import java.util.List;


public class DefaultAuthorizingRealm extends AuthorizingRealm {

    private static final Logger log = LoggerFactory.getLogger(DefaultAuthorizingRealm.class);

    @Autowired
    private AuthorizingDao dao;

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        String principal = (String) principals.getPrimaryPrincipal();
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        // 角色名的集合
        List<String> roles = getUserRols(principal);
        Log.debug(log, "读取用户" + principal + "的角色");
        authorizationInfo.addRoles(roles);
        // 权限名的集合
        List<String> permissions = getUserPermissions(principal);
        Log.debug(log, "读取用户" + principal + "的权限");
        authorizationInfo.addStringPermissions(permissions);
        // 返回带角色和权限的信息
        return authorizationInfo;
    }

    /*
     * 实现用户的认证 可以实现 验证码 限制登录人数 subject.login()时处理
     * @see org.apache.shiro.realm.AuthenticatingRealm#doGetAuthenticationInfo(org.apache.shiro.authc.AuthenticationToken)
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        String principal = (String) token.getPrincipal();
        SimpleAuthenticationInfo info = null;
        if (StringUtils.hasLength(principal)) {
            UsernamePasswordAuthenticationInfo user = dao.getUser4LoginByUserId(principal);

            if (user == null) {
                // 不用系统默认消息
                throw new UnknownAccountException(Log.formatMessage("用户[{}]不存在", principal));
            }

            if (toBoolean(user.getLocked())) {
                // 不用系统默认消息
                throw new LockedAccountException(Log.formatMessage("用户[{}]被锁定", principal));
            }

            if (toBoolean(user.getDisabled())) {
                // 不用系统默认消息
                throw new DisabledAccountException(Log.formatMessage("用户[{}]已禁用", principal));
            }

            /*
             * 交给AuthenticatingRealm使用CredentialsMatcher进行密码匹配，如果觉得人家的不好可以在此判断或自定义实现
             */
            info = new SimpleAuthenticationInfo(user.getUserid(), user.getPassword(), getName());
        }
        return info;
    }

    @Override
    public String getName() {
        return getClass().getName();
    }

    public List<String> getUserRols(String userid) {
        List<String> roles = dao.selectUserRoles(userid);

        if (roles == null) {
            roles = new ArrayList<String>();
        }
        return roles;
    }

    public List<String> getUserPermissions(String userid) {
        List<String> permissions = dao.selectUserPermissions(userid);

        if (permissions == null) {
            permissions = new ArrayList<String>();
        }
        return permissions;
    }

    private static Boolean toBoolean(Object o) {
        boolean r = false;
        if (o != null) {
            r = true;
            if ((o instanceof String)) {
                String tmp = (String) o;
                if ("n".equalsIgnoreCase(tmp))
                    r = false;
                else if ("no".equals(tmp))
                    r = false;
                else if ("0".equals(tmp))
                    r = false;
                else if ("false".equalsIgnoreCase(tmp.toLowerCase())) {
                    r = false;
                }
            }
            if ((o instanceof Integer)) {
                int tmp = ((Integer) o).intValue();
                if (tmp <= 0) {
                    r = false;
                }
            }
            if (o instanceof Boolean) {
                r = (Boolean) o;
            }
        }
        return Boolean.valueOf(r);
    }
}
